// This file is part of the 'texasholdem' project, an open source
// Texas Hold'em poker application written in Java.
//
// Copyright 2009 Oscar Stigter
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file is part of the 'texasholdem' project, an open source
// Texas Hold'em poker application written in Java.
//
// Copyright 2009 Oscar Stigter
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.TexasHoldem.core;

import java.io.IOException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import com.TexasHoldem.ITexasHoldemInterface;
import com.TexasHoldem.ITexasHoldemZoomInterface;
import com.TexasHoldem.TexasHoldemServerEx;
import com.TexasHoldem.ServerData.PokerPlayer;
import com.TexasHoldem.core.actions.*;
import com.TexasHoldem.util.ResourceBundleConfig;
import com.TexasHoldem.util.SpringFactory;

import org.apache.log4j.Logger;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Limit Texas Hold'em poker table. <br />
 * <br />
 * 
 * This class forms the heart of the poker engine. It controls the game flow for
 * a single poker table.
 * 
 * @author Oscar Stigter
 */
public class Table implements Runnable,ITableState
{

	private static final Logger logger = Logger.getLogger(Table.class);

	/** In fixed-limit games, the maximum number of raises per betting round. */
	private static final int MAX_RAISES = 3;

	/** Whether players will always call the showdown, or fold when no chance. */
	private static final boolean ALWAYS_CALL_SHOWDOWN = false;

	/** The players at the table. */
	// private final List<Player> players;
	public final Map<Integer, Player> players;

	/** The active players in the current hand. */
	private final List<Player> activePlayers;

	/** The deck of cards. */
	private final Deck deck;

	/** The community cards on the board. */
	private final List<Card> board;
	

	/** The current dealer position. */
	private int dealerPosition;

	/** The current dealer. */
	private Player dealer;

	/** The position of the acting player. */
	private int actorPosition;

	/** The acting player. */
	private Player actor;

	/** The minimum bet in the current hand. */
	private int minBet;

	/** The current bet in the current hand. */
	private int bet;

	/** All pots in the current hand (main pot and any side pots). */
	private final List<Pot> pots;

	/** The player who bet or raised last (aggressor). */
	private Player lastBettor;

	/** Number of raises in the current betting round. */
	private int raises;

	/** table will be close */
	private boolean bclose = false;

	private boolean bstart = false;
	
	private long allruntime = 0;

	private Lock lock = new ReentrantLock();

	

	private static SimpleDateFormat format = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");

	private TableConfig tableCofing;
	
	private Map<Long,Player> startPlayers = new HashMap<Long, Player>();
	
	private Map<Long,Player> preflopPlayers = new HashMap<Long, Player>();
	
	private Map<Long,Player> flopPlayers = new HashMap<Long, Player>();
	
	private Map<Long,Player> turnPlayers = new HashMap<Long, Player>();
	
	private Map<Long,Player> riversPlayers = new HashMap<Long, Player>();

	
	public ITexasHoldemInterface serverinterface;
	
	public ITexasHoldemZoomInterface zoomInterface;
	
	

	public void setServerinterface(ITexasHoldemInterface serverinterface)
	{
		this.serverinterface = serverinterface;
	}

	public ITexasHoldemInterface getServerinterface()
	{
		return serverinterface;
	}

	public ITexasHoldemZoomInterface getZoomInterface()
	{
		return zoomInterface;
	}

	public void setZoomInterface(ITexasHoldemZoomInterface zoomInterface)
	{
		this.zoomInterface = zoomInterface;
	}

	public TableConfig getTableCofing()
	{
		return tableCofing;
	}

	public void setTableCofing(TableConfig tableCofing)
	{
		this.tableCofing = tableCofing;
	}

	public boolean isBstart()
	{
		return bstart;
	}

	public void setBstart(boolean bstart)
	{
		this.bstart = bstart;
	}

	/**
	 * Constructor.
	 * 
	 * @param bigBlind
	 *            The size of the big blind.
	 */
	public Table(TableConfig tableCofing)
	{
		this.tableCofing = tableCofing;
		players = new HashMap<Integer, Player>();
		activePlayers = new ArrayList<Player>();
		deck = new Deck();
		board = new ArrayList<Card>();
		pots = new ArrayList<Pot>();

	}

	/**
	 * Adds a player.
	 * 
	 * @param player
	 *            The player.
	 */
	public void addPlayer(Player player)
	{
		if(this.lock.tryLock())
		{
			try
			{
				if (player.getPos() == -1)
				{
					for (int pos = 0; pos < this.tableCofing.getLimitPlayerCount(); pos++)
					{
						if (!players.containsKey(pos))
						{
							players.put(pos, player);
							player.setPos(pos);
							break;
						}
					}
				}
				else
				{
					if (players.containsKey(player.getPos()))
					{
						for (int pos = 0; pos < this.tableCofing
								.getLimitPlayerCount(); pos++)
						{
							if (!players.containsKey(pos))
							{
								players.put(pos, player);
								player.setPos(pos);
								break;
							}
						}
					}
					else
					{
						players.put(player.getPos(), player);
					}
				}
			}
			finally 
			{
				lock.unlock();
			}
			

		}

	}

	/**
	 * remove a player.
	 * 
	 * @param player
	 *            The player.
	 */
	public void removePlayer(Player removePlayer)
	{
		if(this.lock.tryLock())
		{
			try
			{
				for (int pos : players.keySet())
				{
					if (players.get(pos) != null && players.get(pos).equals(removePlayer))
					{
						players.remove(pos);
						break;
					}

				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
	}

	/**
	 * 获取当前可以活动的玩家
	 * 
	 * 
	 * @param player
	 *            The player.
	 */
	public int getActivePlayers()
	{
		int noOfActivePlayers = 0;
		if(this.lock.tryLock())
		{
			try
			{
				for (Player player : players.values())
				{
					if (player.getCash() >= this.getTableCofing().getBigBlind())
						noOfActivePlayers++;
					else if (this.getTableCofing().isAutoputmoney())
					{
						player.setCash(this.getTableCofing().getBigBlind() * 100);
						player.getClient().getStatistics().getReBuy().incrementAndGet();
					}
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		return noOfActivePlayers;
	}
	
	public Player getOneActivePlayer()
	{
		
		if(this.lock.tryLock())
		{
			try
			{
				for (Player player : players.values())
				{
					if (player.getCash() >= this.getTableCofing().getBigBlind())
						return player;
					else if (this.getTableCofing().isAutoputmoney())
						player.setCash(this.getTableCofing().getBigBlind() * 100);
					
					
					break;
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		return null;
	}

	/**
	 * 轮询检查玩家是否断线
	 */
	public void CheckDisconnectPlayers()
	{
		List<Player> disconnectlist = null;
		if(this.lock.tryLock())
		{
			try
			{
				for (Player player : players.values())
				{
					if (!player.getClient().IsPlayerOnline())
					{
						if (disconnectlist == null)
							disconnectlist = new ArrayList<Player>();
						disconnectlist.add(player);
					}
					else
					{
						player.getClient().getStatistics().getActiveTime().set(System.currentTimeMillis());
					}

				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		
		if (disconnectlist != null)
		{
			for (Player player : disconnectlist)
			{

				this.removePlayer(player);
				this.notifyPlayerLeaveTable(player);
				player.getClient().getStatistics().getLoginOutTime().set(System.currentTimeMillis());
				player.getClient().getStatistics().getLoginTime().set(0);
				player.getClient().OnDisconnect(player);
				this.getServerinterface().OnDisConnect(player);
				logger.debug("disconnect:" + player.getName() + "\n");
			}
			disconnectlist.clear();

		}
	}

	/**
	 * Main game loop.
	 */
	@Override
	public void run()
	{
		while (!this.isBclose())
		{
			long start = System.currentTimeMillis();
			this.OnReady();
			this.OnStart();
			this.OnPlay();
			this.OnEnd();
			this.allruntime += System.currentTimeMillis() - start;
		}

	}

	/**
	 * Plays a single hand.
	 */
	private void playHand()
	{
		resetHand();

		// Small blind.
		if (activePlayers.size() > 2)
		{
			rotateActor();
		}
		postSmallBlind();

		// Big blind.
		rotateActor();
		postBigBlind();

		// Pre-Flop.
		dealHoleCards();
		logger.debug("dealHoleCards");
		for (Player player : this.activePlayers)
			player.getClient().getStatistics().getPreFlop().incrementAndGet();
		
		doBettingRound();
		
		

		// Flop.
		if (activePlayers.size() > 1)
		{
			for (Player player : this.activePlayers)
				player.getClient().getStatistics().getFlop().incrementAndGet();
			
			bet = 0;
			minBet = this.getTableCofing().getBigBlind();
			dealCommunityCards("Flop", 3);
			logger.debug("dealCommunityCards 3");
			doBettingRound();

			// Turn.
			if (activePlayers.size() > 1)
			{
				bet = 0;
				dealCommunityCards("Turn", 1);
				logger.debug("dealCommunityCards Turn 1");
				// minBet = 2 * this.getTableCofing().getBigBlind();

				doBettingRound();

				// River.
				if (activePlayers.size() > 1)
				{
					bet = 0;
					dealCommunityCards("River", 1);
					logger.debug("dealCommunityCards River 1");
					doBettingRound();

					// Showdown.
					if (activePlayers.size() > 1)
					{
						bet = 0;
						doShowdown();
						

					}
					else
						doFloddown();
				}
				else
					doFloddown();
			}
			else
				doFloddown();
		}
		else
			doFloddown();
	}

	/**
	 * Resets the game for a new hand.
	 */
	private void resetHand()
	{
		// Clear the board.
		this.startPlayers.clear();
		this.preflopPlayers.clear();
		this.flopPlayers.clear();
		this.turnPlayers.clear();
		this.riversPlayers.clear();
		board.clear();
		pots.clear();
		activePlayers.clear();


		synchronized (players)
		{
			for (Player player : players.values())
			{
				player.resetHand();
				if (player.getCash() >= this.getTableCofing().getBigBlind())
				{
	                activePlayers.add(player);
	                startPlayers.put(player.getClient().getId(), player.publicClone());
				}
				
					
			}
		}

		// Rotate the dealer button.
		dealerPosition = (dealerPosition + 1) % activePlayers.size();
		dealer = activePlayers.get(dealerPosition);

		// Shuffle the deck.
		deck.shuffle();

		// Determine the first player to act.
		actorPosition = dealerPosition;
		actor = activePlayers.get(actorPosition);

		// Set the initial bet to the big blind.
		minBet = this.getTableCofing().getBigBlind();
		bet = minBet;

		notifyPlayersTableConfig();
		notifyBoardUpdated();
		//notifyPlayersUpdated(false);
		notifyPlayersDealer(dealer);
		notifyPlayersUpdate();
		
		// notifyMessage("New hand, %s is the dealer.", dealer);

	}
	
	

	/**
	 * Rotates the position of the player in turn (the actor).
	 */
	private void rotateActor()
	{
		actorPosition = (actorPosition + 1) % activePlayers.size();
		actor = activePlayers.get(actorPosition);

		if(this.lock.tryLock())
		{
			try
			{
				for (Player player : players.values())
				{
					player.getClient().actorRotated(this.getTableCofing().getId(),actor, actorPosition);
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		

	}

	/**
	 * Posts the small blind.
	 */
	private void postSmallBlind()
	{
		final int smallBlind = this.getTableCofing().getBigBlind() / 2;
		this.bet = smallBlind;
		actor.postSmallBlind(smallBlind);
		contributePot(smallBlind);
		notifyPlayerActed();
		
		logger.debug(String.format("%s: posts small blind %d",actor.getName(), smallBlind));

	}

	/**
	 * Posts the big blind.
	 */
	private void postBigBlind()
	{
		this.bet = this.getTableCofing().getBigBlind();
		actor.postBigBlind(this.getTableCofing().getBigBlind());
		contributePot(this.getTableCofing().getBigBlind());
		notifyBoardUpdated();
		notifyPlayerActed();
		
		logger.debug(String.format("%s: posts big blind %d",actor.getName(), this.getTableCofing().getBigBlind()));
	}

	
	/**
	 * Deals the Hole Cards.
	 */
	private void dealHoleCards()
	{

		for (Player player : activePlayers)
		{
			player.setCards(deck.deal(2));
			player.getClient().HandUpdate(this.getTableCofing().getId(), player);
		}
	}

	/**
	 * Deals a number of community cards.
	 * 
	 * @param phaseName
	 *            The name of the phase.
	 * @param noOfCards
	 *            The number of cards to deal.
	 */
	private void dealCommunityCards(String phaseName,int noOfCards)
	{
		for (int i = 0; i < noOfCards; i++)
		{
			Card c = deck.deal();
			board.add(c);
		}

		notifyPlayerdealCommunityCards();
	}


	private int getActiveBetPlayers()
	{
		int playersToAct = this.activePlayers.size();
		for(Player player:this.activePlayers)
		{
			if (player.isAllIn())
				playersToAct--;
				
		}
		return playersToAct;
	}
	/**
	 * Performs a betting round.
	 */
	private void doBettingRound()
	{
		// Determine the number of active players.
		int playersToAct = this.activePlayers.size();
		// Determine the initial player and bet size.
		if (board.size() == 0)
		{
			// Pre-Flop; player left of big blind starts, bet is the big blind.
			bet = this.getTableCofing().getBigBlind();
		}
		else
		{
			// Otherwise, player left of dealer starts, no initial bet.
			actorPosition = dealerPosition;
			bet = 0;
		}

		
		
		if(getActiveBetPlayers() <= 1)
			return;

		// bet = 0;
		lastBettor = null;
		notifyBoardUpdated();

		while (playersToAct > 0)
		{
			rotateActor();
			Action action = null;
			if (actor.isAllIn())
			{
				// Player is all-in, so must check.
				action = Action.CHECK;
				playersToAct--;
			}
			else
			{
				// Otherwise allow client to act.
				Set<Action> allowedActions = getAllowedActions(actor);
				String allows = actor.getName() + ":";
				for (Action a : allowedActions)
				{
					allows += a.toString() + ",";
				}
				logger.debug(allows);

				actor.setAction(null);
				synchronized (actor)
				{
					boolean acted = actor.getClient().act(this.getTableCofing().getId(), minBet, bet,allowedActions);
					if (acted)
					{
						try
						{
							actor.wait(this.getTableCofing().getBetTimeOut());
						}
						catch (InterruptedException e)
						{
							e.printStackTrace();
						}
					}

				}

				if (actor.getAction() != null)
				{
					action = actor.getAction();
					logger.debug(",name:" + actor.getName() + ",action:" + action.toString());
				}
				else
				{
					action = Action.FOLD;
					logger.debug(",name:" + actor.getName() + ",action:null fold");
				}
				// Verify chosen action to guard against broken clients
				// (accidental or on purpose).
				if (!allowedActions.contains(action))
				{
					if (action instanceof BetAction && !allowedActions.contains(Action.BET))
					{
						// throw new
						// IllegalStateException(String.format("Player '%s' acted with illegal Bet action",
						// actor));
						action = Action.FOLD;
						logger.debug(String.format("%s: BET Exception Flod\n",actor.getName()));
					}
					else if (action instanceof RaiseAction && !allowedActions.contains(Action.RAISE))
					{
						// throw new
						// IllegalStateException(String.format("Player '%s' acted with illegal Raise action",
						// actor));
						action = Action.FOLD;
						logger.debug(String.format("%s: RAISE Exception Flod\n",actor.getName()));
					}
					else if (action instanceof CheckAction && !allowedActions.contains(Action.CHECK))
					{
						// throw new
						// IllegalStateException(String.format("Player '%s' acted with illegal Raise action",
						// actor));
						action = Action.FOLD;
						logger.debug(String.format("%s: Check Exception Flod\n", actor.getName()));
					}
					
					else if (action instanceof AllInAction && !allowedActions.contains(Action.RAISE) && !allowedActions.contains(Action.BET) && !allowedActions.contains(Action.CALL))
					{
						action = Action.FOLD;
						logger.debug(String.format("%s: AllIn Exception Flod\n", actor.getName()));
					}
				}
				playersToAct--;
				
				if (action == Action.ALL_IN)
				{

					//this.logger.debug((String.format("%s: AllIn %d\n",actor.getName(), actor.getCash())));
					
					contributePot(actor.getCash());
					actor.payCash(actor.getCash());
					actor.setBet(actor.getBet() + actor.getCash());
					
					if(bet < actor.getBet())
						bet = actor.getBet();
					
					if(minBet < actor.getBet())
						minBet = actor.getBet();
					lastBettor = actor;

					// 中间位置bet 其他位置要重新轮询一次
					playersToAct = this.activePlayers.size() - 1;

					
					
					// Do nothing.
				}
				else if (action == Action.CHECK)
				{
					actor.setBet(0);
					//this.logger.debug(String.format("%s: Check\n",actor.getName()));
					// Do nothing.
				}
				else if (action == Action.CALL)
				{
					
					int betIncrement = bet - actor.getBet();
					
					//this.logger.debug((String.format("%s: Call Data BetInc:%d,bet:%d,cash:%d",actor.getName(), betIncrement,bet,actor.getCash())));
					
					//如果其他玩家下注太多超过本身筹码,下注本身筹码,否则就是下注增长部分
					if (betIncrement > actor.getCash())
					{
						
						action.setAmount(actor.getCash());
						
						contributePot(actor.getCash());
						actor.setBet(actor.getBet() + actor.getCash());
						actor.payCash(actor.getCash());
						
						
						//this.logger.debug((String.format(",Call %d\n",actor.getBet())));
					}
					else
					{
						action.setAmount(betIncrement);
						
						contributePot(betIncrement);
						actor.setBet(actor.getBet() + betIncrement);
						actor.payCash(betIncrement);
						
						
						//this.logger.debug((String.format(",Call %d\n",actor.getBet())));
						
					}

				}
				else if (action instanceof BetAction)
				{
					int amount =  action.getAmount();
					if (amount < minBet || amount > actor.getCash())
					{
						action = Action.FOLD;
						//this.logger.debug((String.format("%s: Illegal client Betaction : amount:%d,minBet:%d,cash:%d\n",actor.getName(),amount,minBet,actor.getCash())));
						
						actor.setCards(null);
						activePlayers.remove(actor);

						actorPosition--;
						if (activePlayers.size() == 1)
						{
							playersToAct = 0;
						}
					}
					else
					{
						actor.setBet(amount);
						actor.payCash(amount);
						contributePot(amount);
						bet = amount;
						minBet = amount;
						lastBettor = actor;

						// 中间位置bet 其他位置要重新轮询一次
						playersToAct = this.activePlayers.size() - 1;

						//this.logger.debug((String.format("%s: Bet %d\n",actor.getName(), amount)));
					}

				}
				else if (action instanceof RaiseAction)
				{
					int amount = action.getAmount();
					if (amount < minBet || amount > actor.getCash())
					{
						action = Action.FOLD;
						//this.logger.debug((String.format("%s: Illegal client Raiseaction: amount:%d,minBet:%d,cash:%d\n",actor.getName(),amount,minBet,actor.getCash())));
						
						actor.setCards(null);
						activePlayers.remove(actor);

						actorPosition--;
						if (activePlayers.size() == 1)
						{
							playersToAct = 0;
						}

					}
					else
					{
						
						//this.logger.debug((String.format("%s: Raise amount:%d,bet:%d,minbet:%d,cash:%d\n",actor.getName(), amount,bet,minBet,actor.getCash())));
						// bet += amount;
						bet = amount;
						minBet = amount;
						// int betIncrement = bet - actor.getBet();
						int betIncrement = amount - actor.getBet();
						if (betIncrement > actor.getCash())
							betIncrement = actor.getCash();
						
						// actor.setBet(bet);
						actor.setBet(amount);
						actor.payCash(betIncrement);
						contributePot(betIncrement);
						lastBettor = actor;
						playersToAct = this.activePlayers.size() - 1;
					}

					
				}
				else if (action == Action.FOLD)
				{
					actor.setCards(null);
					activePlayers.remove(actor);
					
					//this.logger.debug((String.format("%s: Fold\n",actor.getName())));
					

					// 如果是zoom 方式就自动切换桌子

					actorPosition--;
					if (activePlayers.size() == 1)
					{
						playersToAct = 0;
					}
				}
				else
				{
					// Programming error, should never happen.
					throw new IllegalStateException("Invalid action: " + action + "," + actor.getName());
				}
				if(actor.getAction() == null)
					actor.setAction(action);
				notifyPlayerActed();
				OnPlayerActed(actor);
				
				if (playersToAct > 0)
					notifyBoardUpdated();
			}
			
			

			
		}

		// Reset player's bets.

			for (Player player : activePlayers)
				player.resetBet(board.size());
		
		notifyBoardUpdated();
		notifyPlayersUpdated(false);

		TableSleep(1000);
	}

	/**
	 * Returns the allowed actions of a specific player.
	 * 
	 * @param player
	 *            The player.
	 * 
	 * @return The allowed actions.
	 */
	private Set<Action> getAllowedActions(Player player)
	{
		Set<Action> actions = new HashSet<Action>();
		if (player.isAllIn())
		{
			actions.add(Action.CHECK);
		}
		else
		{
			int actorBet = actor.getBet();
			// 翻牌后,动作判断
			if (bet == 0)
			{

				
				if (activePlayers.size() >= 2)
				{
					if (actorBet > 0)
					{
						actions.add(Action.CALL);
						actions.add(Action.RAISE);
					}
					else
					{
						actions.add(Action.CHECK);
						actions.add(Action.BET);
					}
				}
			}
			else
			// 翻牌前可允许动作判断
			{
				// 这里判断是否小于大盲注,小于就是小盲注位的动作
				if (actorBet < bet)
				{
					actions.add(Action.CALL);
					if (activePlayers.size() >= 2)
					{
						actions.add(Action.RAISE);
					}
				}
				else
				{
					actions.add(Action.CHECK);
					if (activePlayers.size() >= 2)
					{
						actions.add(Action.RAISE);
					}
				}
			}
			actions.add(Action.FOLD);
		}
		return actions;
	}

	/**
	 * Contributes to the pot.
	 * 
	 * @param amount
	 *            The amount to contribute.
	 */
	public void contributePot(int amount)
	{
		for (Pot pot : pots)
		{
			if (!pot.hasContributer(actor))
			{
				int potBet = pot.getBet();
				if (amount >= potBet)
				{
					// Regular call, bet or raise.
					pot.addContributer(actor);
					amount -= pot.getBet();
				}
				else
				{
					// Partial call (all-in); redistribute pots.
					pots.add(pot.split(actor, amount));
					amount = 0;
				}
			}
			if (amount <= 0)
			{
				break;
			}
		}
		if (amount > 0)
		{
			Pot pot = new Pot(amount);
			pot.addContributer(actor);
			pots.add(pot);
		}
	}
	
	private int getPlayerTotalBet(Player player)
	{
		int total = 0;
		for(Pot pot:this.pots)
		{
			if(pot.hasContributer(player))
			{
				total += pot.getBet();
			}
		}
		return total;
	}

	private void doFloddown()
	{
		Player winner = activePlayers.get(0);
		// Divide winnings.
		StringBuilder winnerText = new StringBuilder();

		Map<Player, Integer> potDivision = new HashMap<Player, Integer>();
		
		List<Player> winplayerids = new ArrayList<Player>();
		int totalPot = getTotalPot();
		winner.win(totalPot);
		winplayerids.add(winner);
		potDivision.put(winner, totalPot);
		
		notifyPlayersWind(winplayerids);
		notifyPlayersUpdated(true);
		
		StringBuilder result = new StringBuilder();
		result.append(String.format("%s win %d\n", winner.getName(),totalPot));
		result.append("*** SUMMARY ***\n");
		result.append(String.format("Main pot %d\n", totalPot));
		result.append(String.format("Board %s\n", this.board.toString()));

		int seat = 1;
		for (Player player : activePlayers)
		{
			result.append(String.format("Seat %d: %s\n", seat,player.GetSummary(potDivision)));
			seat++;
		}
		
		LogTexasProcess(result.toString());
		
		

		if(this.board.size() == 0)
			winner.getClient().getStatistics().getPreFlopWin().addAndGet(totalPot);
		
		
		if(this.board.size() > 0 )
			winner.getClient().getStatistics().getFlopWin().addAndGet(totalPot);
		
		
		winner.getClient().getStatistics().getEveryday_WinCash().addAndGet(totalPot);
		winner.getClient().getStatistics().getWinCash().addAndGet(totalPot);
		winner.getClient().getStatistics().getEveryday_win().incrementAndGet();
		
		
		
		

		TableSleep(1000);
	}

	/**
	 * Performs the showdown.
	 */
	private void doShowdown()
	{
		// Determine show order; start with all-in players...
		// 查找是否有全部下注玩家
		List<Player> showingPlayers = new ArrayList<Player>();
		for (Pot pot : pots)
		{
			for (Player contributor : pot.getContributors())
			{
				if (!showingPlayers.contains(contributor)
						&& contributor.isAllIn())
				{
					showingPlayers.add(contributor);
				}
			}
		}
		// ...then last player to bet or raise (aggressor)...
		// 最后下注玩家或者加注玩家
		if (lastBettor != null)
		{
			if (!showingPlayers.contains(lastBettor))
			{
				showingPlayers.add(lastBettor);
			}
		}
		// ...and finally the remaining players, starting left of the button.
		int pos = (dealerPosition + 1) % activePlayers.size();
		while (showingPlayers.size() < activePlayers.size())
		{
			Player player = activePlayers.get(pos);
			if (!showingPlayers.contains(player))
				showingPlayers.add(player);

			pos = (pos + 1) % activePlayers.size();
		}

		// Players automatically show or fold in order.
		boolean firstToShow = true;
		int bestHandValue = -1;
		for (Player playerToShow : showingPlayers)
		{
			// 计算当前玩家牌手的数值
			Hand hand = new Hand(board);
			hand.addCards(playerToShow.getCards());
			HandValue handValue = new HandValue(hand);
			boolean doShow = ALWAYS_CALL_SHOWDOWN;
			if (!doShow)
			{
				if (playerToShow.isAllIn())
				{
					// All-in players must always show.
					doShow = true;
					firstToShow = false;
				}
				else if (firstToShow)
				{
					// First player must always show.
					doShow = true;
					bestHandValue = handValue.getValue();
					firstToShow = false;
				}
				else
				{
					// Remaining players only show when having a chance to win.
					if (handValue.getValue() >= bestHandValue)
					{
						doShow = true;
						bestHandValue = handValue.getValue();
					}
				}
			}
			if (doShow)
			{
				// Show hand.
				synchronized (players)
				{
					for (Player player : this.players.values())
					{
						player.getClient().ShowCards(this.getTableCofing().getId(), playerToShow);
					}
				}

			}
			else
			{
				// Fold.
				// playerToShow.setCards(null);
				// activePlayers.remove(playerToShow);
				// notifyMessage("%s folds.", playerToShow);
			}
		}

		StringBuilder result = new StringBuilder();
		result.append("***Hand Info***\n");
		// Sort players by hand value (highest to lowest).
		// 根据玩家牌手的值排序
		Map<HandValue, List<Player>> rankedPlayers = new TreeMap<HandValue, List<Player>>();
		for (Player player : activePlayers)
		{
			// Create a hand with the community cards and the player's hole
			// cards.
			Hand hand = new Hand(board);

			hand.addCards(player.getCards());
			// Store the player together with other players with the same hand
			// value.
			HandValue handValue = new HandValue(hand);

			List<Player> playerList = rankedPlayers.get(handValue);
			if (playerList == null)
			{
				playerList = new ArrayList<Player>();
			}
			playerList.add(player);
			rankedPlayers.put(handValue, playerList);
			player.setCurhandValue(handValue);
			
			result.append(String.format("%s handvalue:%d,[%s],(%s)\n",player.getName(), handValue.getValue(),player.getCardsStr(), handValue.getDescription()));
		}

		result.append("***Pots***\n");
		for (Pot pot : pots)
		{
			result.append(pot.toString() + "\n");
		}
		
		Map<Player, Integer> playerTotalBet = new HashMap<Player, Integer>();
		for (Player player : activePlayers)
		{
			playerTotalBet.put(player, this.getPlayerTotalBet(player));
		}
		
		
		// Per rank (single or multiple winners), calculate pot distribution.
		int totalPot = getTotalPot();
		Map<Player, Integer> potDivision = new HashMap<Player, Integer>();
		for (HandValue handValue : rankedPlayers.keySet())
		{
			List<Player> winners = rankedPlayers.get(handValue);
			for (Pot pot : pots)
			{
				// Determine how many winners share this pot.
				int noOfWinnersInPot = 0;
				for (Player winner : winners)
				{
					if (pot.hasContributer(winner))
					{
						noOfWinnersInPot++;
					}
				}
				if (noOfWinnersInPot > 0)
				{
					// Divide pot over winners.
					int potShare = pot.getValue() / noOfWinnersInPot;
					for (Player winner : winners)
					{
						if (pot.hasContributer(winner))
						{
							Integer oldShare = potDivision.get(winner);
							if (oldShare != null)
							{
								potDivision.put(winner, oldShare + potShare);
							}
							else
							{
								potDivision.put(winner, potShare);
							}

						}
					}
					// Determine if we have any odd chips left in the pot.
					int oddChips = pot.getValue() % noOfWinnersInPot;
					if (oddChips > 0)
					{
						// Divide odd chips over winners, starting left of the
						// dealer.
						pos = dealerPosition;
						while (oddChips > 0)
						{
							pos = (pos + 1) % activePlayers.size();
							Player winner = activePlayers.get(pos);
							Integer oldShare = potDivision.get(winner);
							if (oldShare != null)
							{
								potDivision.put(winner, oldShare + 1);
								oddChips--;
							}
						}

					}
					pot.clear();
				}
			}
		}

		// Divide winnings.
		int totalWon = 0;
		List<Player> winplayerids = new ArrayList<Player>();
		for (Player winner : potDivision.keySet())
		{
			int potShare = potDivision.get(winner);
			winner.win(potShare);
			totalWon += potShare;
			
			int playertotal = playerTotalBet.get(winner); 
			if(potShare < playertotal)
			{
				result.append(String.format("%s collected %d,lost %d\n",winner.getName(), potShare,playertotal - potShare));
				winplayerids.add(winner);
			}
			else
			{
				result.append(String.format("%s win %d\n",winner.getName(), potShare));
				winplayerids.add(winner);
			}
			

		}


		// Sanity check.
		if (totalWon != totalPot)
		{
			throw new IllegalStateException("Incorrect pot division!");
		}

		result.append("*** SUMMARY ***\n");
		result.append(String.format("Total pot %d,", totalPot));
		if (potDivision.keySet().size() > 1)
		{
			int Side = 0;
			for (Player winner : potDivision.keySet())
			{
				int potShare = potDivision.get(winner);
				if (Side == 0)
					result.append(String.format("Main pot %d,", potShare));
				else
					result.append(String.format("Side pot-%d %d,", Side,potShare));
				Side++;

			}
		}
		else
		{
			for (Player winner : potDivision.keySet())
			{
				int potShare = potDivision.get(winner);

				result.append(String.format("Main pot %d", potShare));
			}
		}
		result.append("\n");
		result.append(String.format("Board %s\n", this.board.toString()));
		int seat = 1;
		for (Player player : activePlayers)
		{
			result.append(String.format("Seat %d: %s[%s] %s\n",seat,player.getName(),player.getCardsStr(),player.GetSummary(potDivision)));
			seat++;
		}
		notifyPlayersWind(winplayerids);
		notifyPlayersUpdated(true);
		LogTexasProcess(result.toString());
		

		if(this.board.size() > 0 )
		{
			for (Player winner : potDivision.keySet())
			{
				int potShare = potDivision.get(winner);
				int playertotal = playerTotalBet.get(winner); 
				if(potShare > playertotal)
				{
					winner.getClient().getStatistics().getFlopWin().addAndGet(potShare);
					winner.getClient().getStatistics().getEveryday_WinCash().addAndGet(potShare);
					winner.getClient().getStatistics().getWinCash().addAndGet(potShare);
					winner.getClient().getStatistics().getEveryday_win().incrementAndGet();
				}
				
			}
			for (Player player : activePlayers)
			{
				int playertotal = playerTotalBet.get(player); 
				
				if(potDivision.containsKey(player))
				{
					int potShare = potDivision.get(player);
					
					if(potShare < playertotal)
					{
						player.getClient().getStatistics().getFlopLost().addAndGet(playertotal - potShare);
						player.getClient().getStatistics().getEveryday_LostCash().addAndGet(playertotal - potShare);
						player.getClient().getStatistics().getLostCash().addAndGet(playertotal - potShare);
					}
					
					
				}
				else
				{
					player.getClient().getStatistics().getFlopLost().addAndGet(playertotal);
					player.getClient().getStatistics().getEveryday_LostCash().addAndGet(playertotal);
					player.getClient().getStatistics().getLostCash().addAndGet(playertotal);
				}
			}
		}
		

		TableSleep(1000);

	}

	/**
	 * Notifies listeners with a custom game message.
	 * 
	 * @param message
	 *            The formatted message.
	 * @param args
	 *            Any arguments.
	 */
	private void notifyMessage(String message,Object... args)
	{
		message = String.format(message, args);

		if(this.lock.tryLock())
		{
			try
			{
				for (Player player : players.values())
				{
					player.getClient().messageReceived(message);
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
	}

	/**
	 * Notifies clients that the board has been updated.
	 */
	private void notifyBoardUpdated()
	{
		// int pot = getTotalPot();
		if(this.lock.tryLock())
		{
			try
			{
				for (Player player : players.values())
				{
					player.getClient().boardUpdated(this.getTableCofing().getId(),
							board, bet, pots);
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
	}

	/**
	 * Returns the total pot size.
	 * 
	 * @return The total pot size.
	 */
	public int getTotalPot()
	{
		int totalPot = 0;
		for (Pot pot : pots)
		{
			totalPot += pot.getValue();
		}
		return totalPot;
	}

	/**
	 * Notifies clients that one or more players have been updated. <br />
	 * <br />
	 * 
	 * A player's secret information is only sent its own client; other clients
	 * see only a player's public information.
	 * 
	 * @param showdown
	 *            Whether we are at the showdown phase.
	 */
	public void notifyPlayersUpdated(boolean showdown)
	{
		
		if(this.lock.tryLock())
		{
			try
			{
				for (Player self : players.values())
				{
					for (Player player : players.values())
					{
						self.getClient().playerUpdated(this.getTableCofing().getId(), player);
					}

				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}

	}

	/**
	 * Notifies clients that a player has acted.
	 */
	private void notifyPlayerActed()
	{

		if(this.lock.tryLock())
		{
			try
			{
				for (Player p : players.values())
				{
					p.getClient().playerActed(this.getTableCofing().getId(),this.actor);
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}

	}


	/**
	 * Notifies clients that a player enter table.
	 */
	public void notifyPlayerEnterTable(Player enterplayer)
	{
		if(this.lock.tryLock())
		{
			try
			{
				for (Player p : players.values())
				{
					if (!p.equals(enterplayer))
					{
						p.getClient().playerEnterTable(this.getTableCofing().getId(), enterplayer);
					}
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}

	}

	/**
	 * Notifies clients that a player enter table.
	 */
	public void notifyPlayerLeaveTable(Player leaveplayer)
	{
		
		if(this.lock.tryLock())
		{
			try
			{
				for (Player p : players.values())
				{
					p.getClient().playerLeaveTable(this.getTableCofing().getId(),leaveplayer);
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		

	}

	/**
	 * Notifies clients that a player enter table.
	 */
	public void notifyPlayerdealCommunityCards()
	{
		if(this.lock.tryLock())
		{
			try
			{
				for (Player p : players.values())
				{
					p.getClient().dealCommunityCardsUpdate(
							this.getTableCofing().getId(), board);
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		
		

	}

	/**
	 * Notifies clients that one or more players have been updated. <br />
	 * <br />
	 * 
	 * A player's secret information is only sent its own client; other clients
	 * see only a player's public information.
	 * 
	 * @param showdown
	 *            Whether we are at the showdown phase.
	 */
	private void notifyPlayersWind(List<Player> winplayerids)
	{
		
		if(this.lock.tryLock())
		{
			try
			{
				for (Player self : players.values())
				{
					self.getClient().PlayersWinUpdate(this.getTableCofing().getId(), winplayerids);
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}

	}

	private void notifyPlayersDealer(Player player)
	{
		if(this.lock.tryLock())
		{
			try
			{
				for (Player self : players.values())
				{
					self.getClient().PlayersDealer(this.getTableCofing().getId(),player);

				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}

	}
	private void notifyPlayersTableConfig()
	{
		if(this.lock.tryLock())
		{
			try
			{
				for (Player self : players.values())
				{
					self.getClient().TableRoomUpdate(this.getTableCofing());

				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		

	}

	public boolean isBclose()
	{
		return bclose;
	}

	public void setBclose(boolean bclose)
	{
		this.bclose = bclose;
	}

	public int getPlayersCount()
	{
		return this.players.size();
	}

	public String getOtherPlayersJson(Player nogetplayer)
	{
		JSONArray playersdata = new JSONArray();

		synchronized (players)
		{
			for (Player p : players.values())
			{
				if (!p.equals(nogetplayer))
				{
					JSONObject j = new JSONObject();
					j.put("name", p.getName());
					j.put("cash", p.getCash());
					j.put("id", String.valueOf(p.getClient().getId()));
					playersdata.add(j);
				}

			}
		}

		return playersdata.toString();
	}

	/**
	 * @param player
	 * @return 更新桌子上面的玩家信息
	 */
	public void notifyPlayersUpdate()
	{
		
		if(this.lock.tryLock())
		{
			try
			{
				for (Player p : players.values())
				{
					p.getClient().PlayersUpdate(this.getTableCofing().getId(), players.values());
				}
			}
			finally 
			{
				lock.unlock();
			}
			
		}
		
		
	}

	public Map<Integer, Player> getPlayers()
	{
		return players;
	}
	
	public long getPlayerAllCash()
	{
		long allcash = 0;
		synchronized (players)
		{
			for (Player p : players.values())
			{
				allcash += p.getCash();
			}
		}
		return allcash;
	}

	public void TableSleep(long sleep)
	{
		try
		{
			Thread.sleep(sleep);
		}
		catch (InterruptedException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public String toString()
	{
		// TODO Auto-generated method stub
		String data = "id:" + this.getTableCofing().getId() + "\n";
		for (Player p : this.players.values())
		{
			data += p.getName() + ":" + p.getCash() + "\n";
		}
		return data;
	}

	@Override
	public void OnReady()
	{
		// TODO Auto-generated method stub
		this.CheckDisconnectPlayers();
	}

	@Override
	public void OnStart()
	{
		// TODO Auto-generated method stub
		//this.notifyPlayersUpdated(false);
	}

	@Override
	public void OnPlay()
	{
		// TODO Auto-generated method stub
		if (this.getActivePlayers() > 1)
			playHand();
		
	}

	@Override
	public void OnEnd()
	{
		// TODO Auto-generated method stub
		// Game over.
		board.clear();
		pots.clear();
		bet = 0;

		synchronized (players)
		{
			for (Player player : players.values())
				player.resetHand();
		}
		notifyPlayersUpdated(false);
		notifyBoardUpdated();
		
	}

	@Override
	public void OnPlayerActed(Player player)
	{
		// TODO Auto-generated method stub
		if(this.board.size() == 0)//preFlop
		{
			this.preflopPlayers.put(player.getClient().getId(), player.publicClone());
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getPreFlop_Flod().incrementAndGet();
			
			if(player.getAction() == Action.ALL_IN || player.getCash() == 0)
				player.getClient().getStatistics().getPreFlopAllIn().incrementAndGet();
			
			if(player.getAction() instanceof RaiseAction || player.getAction() instanceof BetAction)
				player.getClient().getStatistics().getPreFlopBet().incrementAndGet();
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getPreFlopLost().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getEveryday_LostCash().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getLostCash().addAndGet(this.getPlayerTotalBet(player));
			
		}
		else if(this.board.size() == 3)//Flop
		{
			this.flopPlayers.put(player.getClient().getId(), player.publicClone());
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getFlop_Flod().incrementAndGet();
			
			if(player.getAction() == Action.ALL_IN || player.getCash() == 0)
				player.getClient().getStatistics().getFlopAllIn().incrementAndGet();
			
			if(player.getAction() instanceof RaiseAction || player.getAction() instanceof BetAction)
				player.getClient().getStatistics().getFlopBet().incrementAndGet();
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getFlopLost().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getEveryday_LostCash().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getLostCash().addAndGet(this.getPlayerTotalBet(player));
		}
		else if(this.board.size() == 4)//Turn
		{
			this.turnPlayers.put(player.getClient().getId(), player.publicClone());
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getFlop_Flod().incrementAndGet();
			
			if(player.getAction() == Action.ALL_IN || player.getCash() == 0)
				player.getClient().getStatistics().getFlopAllIn().incrementAndGet();
			
			if(player.getAction() instanceof RaiseAction || player.getAction() instanceof BetAction)
				player.getClient().getStatistics().getFlopBet().incrementAndGet();
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getFlopLost().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getEveryday_LostCash().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getLostCash().addAndGet(this.getPlayerTotalBet(player));
		}
		else if(this.board.size() == 5)//River
		{
			this.riversPlayers.put(player.getClient().getId(), player.publicClone());
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getFlop_Flod().incrementAndGet();
			
			if(player.getAction() == Action.ALL_IN || player.getCash() == 0)
				player.getClient().getStatistics().getFlopAllIn().incrementAndGet();
			
			if(player.getAction() instanceof RaiseAction || player.getAction() instanceof BetAction)
				player.getClient().getStatistics().getFlopBet().incrementAndGet();
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getFlopLost().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getEveryday_LostCash().addAndGet(this.getPlayerTotalBet(player));
			
			if(player.getAction() ==  Action.FOLD)
				player.getClient().getStatistics().getLostCash().addAndGet(this.getPlayerTotalBet(player));
		}
		
	}
	
	public void LogTexasProcess(String resultSummy)
	{
		StringBuilder pokerlog = new StringBuilder();
		
		String LogTextHead = TexasHoldemServerEx.getInstanceConfig().getProperty("LogTextHead");

		pokerlog.append(LogTextHead);
		pokerlog.append("牌局");
		pokerlog.append("#");
		pokerlog.append(TexasHoldemServerEx.getInstance().getPokerids());
		if (getTableCofing().getChampionshipid() == 0)
		{
			pokerlog.append("现金桌子,");
			pokerlog.append("德州扑克无限注,");
			pokerlog.append("(" + this.getTableCofing().getBigBlind() / 2+ "/" + this.getTableCofing().getBigBlind() + ") - ");
			pokerlog.append(format.format(new Date()));
			pokerlog.append("\n");
		}
		else
		{
			pokerlog.append("锦标赛#772064782");
			pokerlog.append("免费锦标赛 ");
			pokerlog.append("德州扑克 无限注,");
			pokerlog.append("第"+ this.getTableCofing().getChampionshipidlevel() + "级");
			pokerlog.append("(" + this.getTableCofing().getBigBlind() / 2 + "/" + this.getTableCofing().getBigBlind() + ") - ");
			pokerlog.append(format.format(new Date()));
			pokerlog.append("\n");
		}

		int seat = 1;
		for(Player player:this.startPlayers.values())
		{
			if (this.getTableCofing().getChampionshipid() == 0)
				pokerlog.append(String.format("Seat %d: %s (%d in cash)\n", seat,player.getName(), player.getCash()));
			else
				pokerlog.append(String.format("Seat %d: %s (%d in chips)\n", seat,player.getName(), player.getCash()));

			seat++;
		}
		pokerlog.append("***PreFlop***\n");
		
		for(Player player:this.preflopPlayers.values())
		{
			if(!player.getActionhis().isEmpty())
			{
				pokerlog.append(player.getName() + ":");
				for(Action action:player.getActionhis())
				{
					if(action.getAmount() != 0)
						pokerlog.append(action.getName() + "(" + action.getAmount() + "),");
					else
						pokerlog.append(action.getName() + ",");
				}
				pokerlog.append("\n");
			}
		}
		if(this.board.size() >= 3)
			pokerlog.append("***Flop***" + String.format("[%s, %s, %s]", this.board.get(0),this.board.get(1),this.board.get(2)) + "\n");
		else
			pokerlog.append("***Flop***\n");
		
		for(Player player:this.flopPlayers.values())
		{
			if(!player.getActionhis().isEmpty())
			{
				pokerlog.append(player.getName() + ":");
				for(Action action:player.getActionhis())
				{
					if(action.getAmount() != 0)
						pokerlog.append(action.getName() + "(" + action.getAmount() + "),");
					else
						pokerlog.append(action.getName() + ",");
				}
				pokerlog.append("\n");
			}
		}
		
		if(this.board.size() >= 4)
			pokerlog.append("***Turn***" + String.format("[%s, %s, %s, %s]", this.board.get(0),this.board.get(1),this.board.get(2),this.board.get(3)) + "\n");
		else
			pokerlog.append("***Turn***\n");

		
		for(Player player:this.turnPlayers.values())
		{
			if(!player.getActionhis().isEmpty())
			{
				pokerlog.append(player.getName() + ":");
				for(Action action:player.getActionhis())
				{
					if(action.getAmount() != 0)
						pokerlog.append(action.getName() + "(" + action.getAmount() + "),");
					else
						pokerlog.append(action.getName() + ",");
				}
				pokerlog.append("\n");
			}
		}
		
		if(this.board.size() >= 5)
			pokerlog.append("***River***" + this.board.toString() + "\n");
		else
			pokerlog.append("***River***\n");
		
		
		
		for(Player player:this.riversPlayers.values())
		{
			if(!player.getActionhis().isEmpty())
			{
				pokerlog.append(player.getName() + ":");
				for(Action action:player.getActionhis())
				{
					if(action.getAmount() != 0)
						pokerlog.append(action.getName() + "(" + action.getAmount() + "),");
					else
						pokerlog.append(action.getName() + ",");
				}
				pokerlog.append("\n");
			}
		}
		
		pokerlog.append(resultSummy);
		logger.info(pokerlog.toString());
		
	}

	public long getAllruntime()
	{
		return allruntime;
	}
	
	public Player getActor()
	{
		return actor;
	}

	public void setActor(Player actor)
	{
		this.actor = actor;
	}

	public static void main(String[] args)
	{
		Player test1 = new Player("suwei_4", 60, new PokerPlayer(1));
		Player test2 = new Player("Suw", 206, new PokerPlayer(2));
		Player test3 = new Player("suwei_3", 237, new PokerPlayer(3));
		List<Card> t = new ArrayList<Card>();
		t.add(new Card("Ad"));
		t.add(new Card("3s"));
		test1.setCards(t);
		List<Card> t2 = new ArrayList<Card>();
		t2.add(new Card("7s"));
		t2.add(new Card("5s"));
		test2.setCards(t2);
		
		TableConfig tableconfig = new TableConfig();
		tableconfig.setId(1);
		Table table = new ZoomTable(tableconfig);
		
		table.board.add(new Card("6s"));
		table.board.add(new Card("6d"));
		table.board.add(new Card("As"));
		table.board.add(new Card("7c"));
		table.board.add(new Card("2c"));
		
		table.addPlayer(test1);
		table.addPlayer(test2);
		
		table.activePlayers.add(test1);
		table.activePlayers.add(test2);
		
		table.setActor(test2);
		table.contributePot(1);
		
		table.setActor(test3);
		table.contributePot(2);
		
		table.setActor(test1);
		table.contributePot(2);
		
		table.setActor(test2);
		table.contributePot(1);
		
		table.setActor(test2);
		table.contributePot(4);
		
		table.setActor(test1);
		table.contributePot(4);
		
		table.setActor(test1);
		table.contributePot(8);
		
		table.setActor(test2);
		table.contributePot(8);
		
		table.setActor(test1);
		table.contributePot(9);
		
		table.setActor(test2);
		table.contributePot(9);
		
		table.doShowdown();
		
		
		
		
	}
}
